package ch.ffhs.services;

import java.net.Socket;
import java.net.SocketAddress;
import java.net.InetSocketAddress;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

/**
 * class ServerWebservice. Implements communication with monitoring-server.
 * 
 * @author mf
 */
public class ServerWebservice {
	// webservice default definition
	private String HOST = "10.0.2.2";
	private Integer PORT = 8080;
	private final String METHOD_NAME = "sendState";

	// webservice params
	private final String ACTIVE = "ACTIVE";
	private final String DAYMODUS = "DAYMODUS";
	private final String ALARMLEVEL = "ALARMLEVEL";
	private final String LATITUDE = "LATITUDE";
	private final String LONGITUDE = "LONGITUDE";

	private Context context;
	private Boolean isOnline = false;

	private Boolean active = false;
	private Boolean dayModus = true; // day = true, night = false
	private Integer alarmLevel = 0;
	private GpsPosition gpsPosition;

	private String getNameSpace() {
		return "http://" + HOST + ":" + PORT.toString()
				+ "/OttosServer/services/";
	}

	private String getWSDL() {
		return "http://" + HOST + ":" + PORT.toString()
				+ "/OttosServer/services/OttosServer?wsdl";
	}

	private String getSoapAction() {
		return "http://" + HOST + ":" + PORT.toString()
				+ "/OttosServer/services/OttosServer/" + METHOD_NAME;
	}

	public void setActive(Boolean active) {
		this.active = active;
	}

	public void setDayModus(Boolean dayModus) {
		this.dayModus = dayModus;
	}

	public void setAlarmLevel(Integer alarmLevel) {
		this.alarmLevel = alarmLevel;
	}

	public ServerWebservice(Context context, GpsPosition gpsPosition) {
		this.context = context;
		this.gpsPosition = gpsPosition;
		loadSettings();
	}

	private void loadSettings() {
		// load webservice settings
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(context);
		HOST = prefs.getString("settingServerUrl", "10.0.2.2");
		PORT = Integer.parseInt(prefs.getString("settingServerPort", "8080"));
	}

	/**
	 * submits the state of the app to the server
	 * 
	 * @param active
	 *            indicates, if the app is activated or deactivated in settings
	 * @param modusDay
	 *            indicates, if the day or night mode is activated (day = true,
	 *            night = false)
	 */
	public void submitState() {
		SubmitState task = new SubmitState();
		task.execute();
	}

	/**
	 * Implements the AsyncTask for submitting data to server
	 * 
	 * @author mf
	 */
	private class SubmitState extends AsyncTask<Void, Void, Integer> {

		private final Integer WS_SUCCESS = 0;
		private final Integer WS_ERROR_NO_CONNECTON = 1;
		private final Integer WS_ERROR_SERVICE_FAILURE = 2;

		@Override
		protected void onPreExecute() {
			loadSettings();
			Log.d("SubmitState", "onPreExecute");
			// check connection-settings
			Toast.makeText(context, "Update State to Cloud", Toast.LENGTH_SHORT)
					.show();

		}

		@Override
		protected void onPostExecute(Integer result) {
			if (!isCancelled()) {
				Log.d("SubmitState", "onPostExecute");
				switch (result) {
				case 0:
					Toast.makeText(context, "Cloud updated", Toast.LENGTH_SHORT)
							.show();
					break;
				case 1:
					Toast.makeText(
							context,
							ch.ffhs.activities.R.string.webservice_no_connection,
							Toast.LENGTH_LONG).show();
					break;
				case 3:
					Toast.makeText(context,
							"Cloud not updated, error occured!",
							Toast.LENGTH_LONG).show();
					break;
				}
			}
		}

		@Override
		protected Integer doInBackground(Void... arg0) {
			if (!isHostRechable()) {
				return WS_ERROR_NO_CONNECTON;
			} else if (sendState()) {
				return WS_SUCCESS;
			} else {
				return WS_ERROR_SERVICE_FAILURE;
			}
		}

		private boolean isHostRechable() {
			try {
				SocketAddress sockaddr = new InetSocketAddress(HOST, PORT);
				// Create an unbound socket
				Socket sock = new Socket();

				// This method will block no more than timeoutMs.
				// If the timeout occurs, SocketTimeoutException is thrown.
				int timeoutMs = 2000; // 2 seconds
				sock.connect(sockaddr, timeoutMs);
				sock.close();
				isOnline = true;
				return true;
			} catch (Exception e) {
				// e.printStackTrace();
				Log.d("ServerWebservice", "Host not reachable");
				isOnline = false;
				return false;
			}
		}
	}

	/**
	 * implements sending via soap-protocol
	 */
	private Boolean sendState() {
		if (!isOnline) {
			return false;
		}

		Log.d("ServerWebservice", "Soapaction: " + getSoapAction());

		// Create request
		SoapObject request = new SoapObject(getNameSpace(), METHOD_NAME);

		// set params
		// active
		PropertyInfo activePI = new PropertyInfo();
		activePI.setName(ACTIVE);
		activePI.setValue(this.active);
		activePI.setType(boolean.class);
		request.addProperty(activePI);

		// daymodus
		PropertyInfo daymodusPI = new PropertyInfo();
		daymodusPI.setName(DAYMODUS);
		daymodusPI.setValue(this.dayModus);
		daymodusPI.setType(boolean.class);
		request.addProperty(daymodusPI);

		// alarm-level
		PropertyInfo alarmLevelPI = new PropertyInfo();
		alarmLevelPI.setName(ALARMLEVEL);
		alarmLevelPI.setValue(this.alarmLevel);
		alarmLevelPI.setType(int.class);
		request.addProperty(alarmLevelPI);

		// latitude
		String lat = "";
		String lon = "";
		if ((gpsPosition != null) && (gpsPosition.getLocation() != null)) {
			lat = Double.toString(gpsPosition.getLocation().getLatitude());
			lon = Double.toString(gpsPosition.getLocation().getLongitude());
		}
		PropertyInfo latitudePI = new PropertyInfo();
		latitudePI.setName(LATITUDE);
		latitudePI.setValue(lat);
		latitudePI.setType(String.class);
		request.addProperty(latitudePI);

		// longitude
		PropertyInfo longitudePI = new PropertyInfo();
		longitudePI.setName(LONGITUDE);
		longitudePI.setValue(lon);
		longitudePI.setType(String.class);
		request.addProperty(longitudePI);

		// Create envelope
		SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
				SoapEnvelope.VER11);
		envelope.dotNet = true;
		// Set output SOAP object
		envelope.setOutputSoapObject(request);
		// Create HTTP call object
		HttpTransportSE androidHttpTransport = new HttpTransportSE(getWSDL());
		try {
			androidHttpTransport.call(getSoapAction(), envelope);
			// Get the response
			SoapPrimitive response = (SoapPrimitive) envelope.getResponse();
			// Assign it to result
			String result = response.toString();
			Log.d("ServerWebservice", result);

			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
}
